//
//  CAEmitterLayerViewController.m
//  CoreAnimation
//
//  Created by 张国文 on 16/10/18.
//  Copyright © 2016年 hangzhouyijiyin. All rights reserved.
//

#import "CAEmitterLayerViewController.h"
#import "UIDevice+XJDevice.h"

@interface CAEmitterLayerViewController ()

@property (nonatomic, strong) UIView *backgroundView;
@property (nonatomic, strong) CALayer *velocityIntroduceImageLayer; // 速度分析图

@end

@implementation CAEmitterLayerViewController

/**
 * 在演示粒子效果之前，我要先吐槽一下，粒子效果这个东西属性是什么意思很容易懂，但是怎么给属性赋值，赋值多大这个不好把握，网上的粒子效果如出一辙，都是粘贴复制，到底发博客那个人懂了没有我不好说，但是我今天要给大家讲解的是我根据长时间的代码测试的出来的结论。
 1、发射的方向由emitterShape和emitterMode决定，这两个属性的组合方式有24种，并且每种组合的发射方向没有规律可言，我制作了一个表列出了每种组合的方向(这里所说的发射方向是Y轴的0方向)，你可以根据emissionLongitude 这个属性在方向的基础上更改粒子发射方向。
 2、所有设置range字眼的都是根据原来你设置的属性+-。
 3、从屏幕上消失的粒子有可能会回来(这个一会在代码里有讲解)。
 4、一些属性继承传递相乘，比如：scale，其他需要你们写代码自己找。

 */

- (BOOL)shouldAutorotate
{
    return NO;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskLandscapeLeft;
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    [UIDevice setOrientation:UIInterfaceOrientationPortrait];
}


- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.view.backgroundColor = [UIColor whiteColor];
    
    self.backgroundView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.frame.size.height, self.view.frame.size.width)];
    self.backgroundView.backgroundColor = [[UIColor grayColor] colorWithAlphaComponent:0.5];
    [self.view addSubview:_backgroundView];
    
    UIButton *returnButton = [UIButton buttonWithType:UIButtonTypeCustom];
    returnButton.frame = CGRectMake(10, 10, 100, 30);
    [returnButton setTitle:@"返回" forState:UIControlStateNormal];
    returnButton.backgroundColor = [UIColor cyanColor];
    [returnButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [returnButton addTarget:self action:@selector(returnBack:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:returnButton];
    
    UIButton *button1 = [UIButton buttonWithType:UIButtonTypeCustom];
    button1.frame = CGRectMake(120, 10, 160, 30);
    [button1 setTitle:@"创建简单火焰效果" forState:UIControlStateNormal];
    button1.backgroundColor = [UIColor yellowColor];
    [button1 setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [button1 addTarget:self action:@selector(createCAReplicator:) forControlEvents:UIControlEventTouchUpInside];
    button1.tag = 100;
    [self.view addSubview:button1];
    
    UIButton *button2 = [UIButton buttonWithType:UIButtonTypeCustom];
    button2.frame = CGRectMake(290, 10, 150, 30);
    [button2 setTitle:@"创建雪花" forState:UIControlStateNormal];
    button2.backgroundColor = [UIColor yellowColor];
    [button2 setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [button2 addTarget:self action:@selector(createCAReplicator:) forControlEvents:UIControlEventTouchUpInside];
    button2.tag = 101;
    [self.view addSubview:button2];
    
    UIButton *button3 = [UIButton buttonWithType:UIButtonTypeCustom];
    button3.frame = CGRectMake(450, 10, 150, 30);
    [button3 setTitle:@"显示速度分析图" forState:UIControlStateNormal];
    button3.backgroundColor = [UIColor yellowColor];
    [button3 setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [button3 addTarget:self action:@selector(createCAReplicator:) forControlEvents:UIControlEventTouchUpInside];
    button3.tag = 102;
    [self.view addSubview:button3];
    
    UIButton *button4 = [UIButton buttonWithType:UIButtonTypeCustom];
    button4.frame = CGRectMake(120, 50, 180, 30);
    [button4 setTitle:@"火焰" forState:UIControlStateNormal];
    button4.backgroundColor = [UIColor yellowColor];
    [button4 setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [button4 addTarget:self action:@selector(createCAReplicator:) forControlEvents:UIControlEventTouchUpInside];
    button4.tag = 103;
    [self.view addSubview:button4];
    
    UIButton *button5 = [UIButton buttonWithType:UIButtonTypeCustom];
    button5.frame = CGRectMake(310, 50, 180, 30);
    [button5 setTitle:@"烟花" forState:UIControlStateNormal];
    button5.backgroundColor = [UIColor yellowColor];
    [button5 setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [button5 addTarget:self action:@selector(createCAReplicator:) forControlEvents:UIControlEventTouchUpInside];
    button5.tag = 104;
    [self.view addSubview:button5];
    
  
    
}

- (void)returnBack:(UIButton *)button
{
    [self dismissViewControllerAnimated:YES completion:nil];
}

- (void)createCAReplicator:(UIButton *)button
{
    for (int i = 0; i < self.backgroundView.layer.sublayers.count; i++) {
        if ([self.backgroundView.layer.sublayers[i] isMemberOfClass:[CAEmitterLayer class]]) {
            [self.backgroundView.layer.sublayers[i] removeFromSuperlayer];
        }
    }
    if (self.velocityIntroduceImageLayer != nil) {
        [self.velocityIntroduceImageLayer removeFromSuperlayer];
    }
    switch (button.tag) {
        case 100:
        {
            // 创建简单的火焰效果
            [self createSimpleFireEffect];
            break;
        }
        case 101:
        {
            // 创建雪花
            [self createSnowFlake];
            break;
        }
        case 102:
        {
            // 显示速度分析题
            [self showVelocityAnalyze];
            break;
        }
        case 103:
        {
            // 创建火焰
            [self createFlame];
            break;
        }
        case 104:
        {
            // 创建烟花
            [self createFireWork];
            break;
        }
        default:
            break;
    }
    for (int i = 0; i < self.view.subviews.count; i++) {
        if ([self.view.subviews[i] isKindOfClass:[UIButton class]]) {
            [self.view bringSubviewToFront:self.view.subviews[i]];
        }
    }
    
}

// 创建简单的火焰效果
- (void)createSimpleFireEffect
{
    CAEmitterLayer *emitter = [CAEmitterLayer layer];
    emitter.frame = self.backgroundView.bounds;
    [self.backgroundView.layer addSublayer:emitter];
    
    // 设置渲染的效果
    emitter.renderMode = kCAEmitterLayerAdditive; // 设置重叠的效果
    // 设置发射器的位置
    emitter.emitterPosition = CGPointMake(self.backgroundView.center.x, self.backgroundView.center.y + 20);
    
    // 设置发射单元
    CAEmitterCell *cell = [[CAEmitterCell alloc] init];
    cell.contents = (__bridge id _Nullable)([UIImage imageWithName:@"Fire"].CGImage);
    cell.birthRate = 150; // 每一秒钟产生的数量
    cell.lifetime = 5.0; // 每个单元的生存周期
    cell.color = [UIColor colorWithRed:1 green:0.5 blue:0.1 alpha:1.0].CGColor;
    cell.alphaSpeed = -0.4; // 每秒钟透明度递减0.4
    cell.velocity = 50;
    cell.velocityRange = 0; // 速度的容差
    cell.emissionRange = 2 * M_PI; // 发射的范围
    
    emitter.emitterCells = @[cell];
}

// 创建雪花
- (void)createSnowFlake
{
    CAEmitterLayer *emitter = [CAEmitterLayer layer];
 //   emitter.frame = self.backgroundView.bounds;
    [self.backgroundView.layer addSublayer:emitter];
    
    emitter.emitterShape = kCAEmitterLayerLine; // 发射的形状，我让他从一条线发出
    emitter.emitterMode = kCAEmitterLayerOutline; // 发射的模式，我让他从发射器的表面发出
    emitter.emitterSize = CGSizeMake(self.backgroundView.bounds.size.width, 100);
    emitter.emitterPosition = CGPointMake(self.backgroundView.bounds.size.width / 2, 110);
    
   // 开始创建发射单元
    CAEmitterCell *snowFlake = [CAEmitterCell emitterCell];
    snowFlake.emissionLongitude = M_PI; // 意思是设置向下方向为正方向。
    snowFlake.contents = (__bridge id _Nullable)([UIImage imageWithName:@"snowFlake"].CGImage);
    snowFlake.birthRate = 2.0;
#pragma mark - 代码一，不会出现向上的雪花
    snowFlake.lifetime = 21.0;
    snowFlake.velocity = 20.0; // 每秒钟20个位点
    snowFlake.velocityRange = 5.0; // 速度的变化范围意思是15~25
    snowFlake.yAcceleration = -0.5; // Y轴加速度方向，没秒钟速度减小0.05，现在运行看见是不是有的雪花向下，有的向上呢
    
#pragma mark  -代码二,会出现向上的雪花
//    snowFlake.lifetime = 50.0;
//    snowFlake.velocity = 20.0; // 每秒钟20个位点
//    snowFlake.velocityRange = 5.0; // 速度的变化范围意思是15~25
//    snowFlake.yAcceleration = -0.5; // Y轴加速度方向，没秒钟速度减小0.05，现在运行看见是不是有的雪花向下，有的向上呢
    
    snowFlake.emissionRange = M_PI_4;
    
    snowFlake.color	=  [UIColor whiteColor].CGColor; // 设置颜色
    snowFlake.spinRange = M_PI / 5; // 每秒旋转0~36度
    
    snowFlake.scale = 0.4; // 设置snowFlake为原图片大小的多少
    snowFlake.scaleRange = 0.2; // 生成的雪花为0.2~0.6的大小
    snowFlake.scaleSpeed = 0.01;
    emitter.emitterCells = @[snowFlake];
    
    
    /**
     *   ok看到这里相信大家对出现向上的雪花和不出现向上的雪花有点不明白，现在我跟大家详细的说说原因。
         请你仔细看看代码一和代码二，你会发现他们的不同点只是lifetime的不同，那么lifetime对粒子有什么影响呢？lifetime就是粒子的生存周期，在代码一中我将生存周期lifetime设置为21.0，你可以将它设置为大于21.0的数，你就会发现有向上的雪花(当然越大越明显了)。
     在图中你会发现我们设置的Y轴向下的速度为20，但是我设置了发射的角度为45度，那么就是说Y轴分速度最慢的就是10√2(10倍根号2)，又因为我设置了Y轴的加速度为-0.5，意思就是说经过28秒左右的时候，Y轴的速度就会为0，这个时候如果设置lifetime大于28，就会出现向上的雪花。但是为什么设置22秒就会出现向上的雪花呢，原因是因为我设置了velocityRange=5.0，意思就是说速度的发射范围在15~25之间，取最慢的速度15，经过上面的运算，lifetime=21.0就是临界值，大于21.0就会出现向上的雪花，相信到这里，大家应该明白lifetime、velocity、velocityRange、yAcceleration之间的关系了吧。
     我的经验：一般来说lifetime的值不要设置的太大，只要粒子经过屏幕就够了，就可以让它消失了，因此我们不用每设置粒子效果就专门的计算lifetime的临界值。
     */
    

}

// 显示速度分析图
- (void)showVelocityAnalyze
{
    // 速度分析图
   
    self.velocityIntroduceImageLayer = [CALayer layer];
    
    self.velocityIntroduceImageLayer.bounds = CGRectMake(0, 0, 300, 300);
    self.velocityIntroduceImageLayer.position = CGPointMake(self.backgroundView.center.x, 200);
    self.velocityIntroduceImageLayer.contents = (__bridge id _Nullable)([UIImage imageWithName:@"velocityIntroduce"].CGImage);
    [self.backgroundView.layer addSublayer:_velocityIntroduceImageLayer];
    
}

// 创建火焰
- (void)createFlame
{
    // 烟
    CAEmitterLayer *smokeCAETLayer = [[CAEmitterLayer alloc] init];
    smokeCAETLayer.emitterPosition = CGPointMake(self.backgroundView.center.x, self.backgroundView.bounds.size.height - 30);
    smokeCAETLayer.emitterSize = CGSizeMake(70, 0);
    smokeCAETLayer.emitterMode = kCAEmitterLayerPoints;
    [self.backgroundView.layer addSublayer:smokeCAETLayer];
    // 火
    CAEmitterLayer *fireCAETLayer = [[CAEmitterLayer alloc] init];
    fireCAETLayer.emitterSize = CGSizeMake(30, 0);
    fireCAETLayer.emitterPosition = CGPointMake(self.backgroundView.center.x, self.backgroundView.bounds.size.height - 30);
    fireCAETLayer.emitterShape = kCAEmitterLayerLine;
    fireCAETLayer.emitterMode = kCAEmitterLayerVolume;
    fireCAETLayer.renderMode = kCAEmitterLayerAdditive;
    [self.backgroundView.layer addSublayer:fireCAETLayer];
  
    
    // 火焰的baseCell
    CAEmitterCell *fireBaseCell = [[CAEmitterCell alloc] init];
    fireBaseCell.birthRate = 200;
    fireBaseCell.lifetime = 20;
    fireBaseCell.velocity = -50; // 刚开始速度方向朝下的
    fireBaseCell.yAcceleration = -150; // 这样设置的话速度一开始向下，然后短时间内向上，这样就形成了一团火
    fireBaseCell.scale  = 0.3;
    fireBaseCell.scaleSpeed = 0.2;
    fireBaseCell.emissionRange = 5;
    fireBaseCell.contents = (__bridge id _Nullable)([UIImage imageWithName:@"Fire"].CGImage);
    fireBaseCell.color = [UIColor colorWithRed:0.8 green:0.4 blue:0.2 alpha:1].CGColor;
    fireBaseCell.alphaSpeed = -0.7;
    
    fireCAETLayer.emitterCells = @[fireBaseCell];
    
    // 烟的baseCell
    CAEmitterCell *smokeBaseCell = [[CAEmitterCell alloc] init];
    smokeBaseCell.emissionLongitude = -M_PI_2;
    smokeBaseCell.birthRate = 20;
    smokeBaseCell.lifetime = 20;
    smokeBaseCell.velocity = -30; // 烟的速度比火慢点
    smokeBaseCell.yAcceleration = -110;
    smokeBaseCell.scale = 0.1;
    smokeBaseCell.scaleSpeed = 0.3;
    smokeBaseCell.emissionRange = M_PI_2 * 3 / 4;
    smokeBaseCell.contents =  (__bridge id _Nullable)([UIImage imageWithName:@"smoke"].CGImage);
   
    smokeBaseCell.color = [UIColor whiteColor].CGColor;
    smokeBaseCell.alphaSpeed = -0.3;
    smokeCAETLayer.emitterCells = @[smokeBaseCell];
    
    
    
    
}

// 创建烟花，这里用到了CAEmitterCell继承的概念
- (void)createFireWork
{
    /**
     *在创建烟花之前，我要说一下创建烟花的思路：步骤一、我们需要设置发射器，发射炮弹。步骤二、在每个炮弹的末端要让炮弹爆炸，我们需要创建这样一个炮弹爆炸的CAEmitterCell。步骤三、炮弹爆炸后产生火花。 根据这个思路我们需要创建3中CAEmitterCell，一是炮弹，二是炮弹爆炸，三是爆炸的火花
     ok，可能有人要说了，为什么要有步骤二，直接让炮弹爆炸产生火花不就行了？这里就涉及到了birthRate这个属性的含义了，birthRate是每秒生成的数量，我们把它设置为1，意思是在1秒的时候产生一个cell，这样是没问题的，那么birthRate等于2呢？birthRate等于2并不是在1秒的时候同时产生2个cell，而是系统把1秒平均分成2份，即在0.5秒的时候产生一个，在1秒的时候产生一个。
     因此如果我们省略步骤二，直接将炮弹爆炸的cell添加到炮弹中，这样的结果就是炮弹边发射边爆炸，这样就达不到我们想要的结果了。
     步骤二相当于继承于步骤一中创建的炮弹，一个烟花爆炸之前的载体，在炮弹发射以后只有炮弹爆炸以后才会执行烟花散开的效果(步骤三)，并且重写birthRate和 lifetime的方法，这样步骤三的火花相当于继承与步骤二中创建的cell，这样相当于独立于步骤一中创建的炮弹，通过这样我们可以设置步骤三中多种烟花的爆炸的效果，就相当于多态了。好吧说到这里有可能你还糊里糊涂的，下面我将通过代码进行展示。
     */
    
    // 创建发射器
    CAEmitterLayer *fireworkEmitter = [CAEmitterLayer layer];
    fireworkEmitter.emitterSize = CGSizeMake(self.backgroundView.bounds.size.width / 3, 0);
    fireworkEmitter.emitterPosition = CGPointMake(self.backgroundView.center.x, self.backgroundView.bounds.size.height - 5);
    fireworkEmitter.emitterMode = kCAEmitterLayerOutline;
    fireworkEmitter.emitterShape = kCAEmitterLayerLine;
    [self.backgroundView.layer addSublayer:fireworkEmitter];
    
    // 步骤一创建炮弹
    CAEmitterCell *bulletCell = [CAEmitterCell emitterCell];
    bulletCell.birthRate = 1; // 每秒产生一个炮弹
    bulletCell.lifetime = 1.04;
    bulletCell.emissionRange = M_PI_4;
    bulletCell.velocity = 250;
    bulletCell.scale = 0.2;
    bulletCell.contents =(__bridge id _Nullable)([UIImage imageWithName:@"bullet"].CGImage);
    
    bulletCell.color = [UIColor redColor].CGColor;
    bulletCell.greenRange = 1.0;
    bulletCell.redSpeed = 1.0;
    bulletCell.blueRange = 1.0;
    fireworkEmitter.emitterCells = @[bulletCell];
    
    // 步骤二创建炮弹爆炸
    CAEmitterCell *burstCell = [CAEmitterCell emitterCell];
    burstCell.birthRate = 1; // 在炮弹的生存周期的1.0节点会创建一个炮弹爆炸的效果，一般来说父类的生存周期应该大于产生一个子类需要的时间,因此bullet.lifetime = 1.02.
    burstCell.lifetime = 0.2;
    burstCell.scale = 2;
    // 这里我们可以更改从步骤一继承过来的炮弹的颜色
    burstCell.greenSpeed = 2.0;
    burstCell.redSpeed = 2.0;
    burstCell.blueSpeed = 2.0;
    burstCell.contents = (__bridge id _Nullable)([UIImage imageWithName:@"bullet"].CGImage);
    bulletCell.emitterCells = @[burstCell]; // 将炮弹爆炸作为炮弹的儿子这样才能继承
    
    // 步骤三 创建炮弹爆炸后的火花
    CAEmitterCell *sparkCell = [CAEmitterCell emitterCell];
    sparkCell.birthRate = 400; // 1秒钟产生400个，但是由于父类的lifetime=0.2，因此实际只有80个火花
    sparkCell.lifetime = 3.0;
    sparkCell.velocity = 120;
    sparkCell.scale = 2.5;
    sparkCell.yAcceleration = 50;
    sparkCell.emissionRange = 2 * M_PI;
    sparkCell.scaleSpeed = -0.2;
    sparkCell.redSpeed = 0.3;
    sparkCell.greenSpeed = 0.3;
    sparkCell.blueSpeed = 0.3;
    sparkCell.alphaSpeed = -0.3;
    sparkCell.contents = (__bridge id _Nullable)([UIImage imageWithName:@"fireStar"].CGImage);
    burstCell.emitterCells = @[sparkCell]; // 将火花作为炮弹爆炸的儿子，大部分操作都是在炮弹爆炸的基础上操作的
    
    
}

@end
